package com.rj.util;

import com.rj.core.constant.CompareType;
import com.rj.core.constant.DateFormat;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 通用校验工具
 *
 * @author YFX_RANLUBO
 * @date 2022/05/26 14:20
 **/
public class VerifyUtils {
    /**
     * 其他判定操作处理
     *
     * @param allowNull
     * @param value
     * @param func
     * @return
     */
    public static boolean notNull(boolean allowNull, Object value, Function<Object, Boolean> func) {
        if (notNull(value)) {
            return func.apply(value);
        }
        return allowNull;
    }

    /**
     * 不是空对象
     *
     * @param value
     * @return
     */
    public static boolean notNull(Object value) {
        return Objects.nonNull(value);
    }

    /**
     * 字符空判定
     *
     * @param allowEmpty 是否允许空值
     * @param value      值
     * @return
     */
    public static boolean empty(boolean allowEmpty, Object value) {
        return allowEmpty ? true : notEmpty((String) value);
    }

    /**
     * 对象空判定
     *
     * @param allowNull 是否允许空值
     * @param value     值
     * @return
     */
    public static boolean nvl(boolean allowNull, Object value) {
        return allowNull ? true : notNull(value);
    }

    /**
     * 是空字符
     *
     * @param value
     * @return
     */
    public static boolean isEmpty(String value) {
        return isNull(value) || value.isEmpty();
    }

    /**
     * 是空集合
     *
     * @param value
     * @return
     */
    public static boolean isEmpty(Collection value) {
        return isNull(value) || value.isEmpty();
    }

    /**
     * 是空集合
     *
     * @param value
     * @return
     */
    public static boolean notEmpty(Collection value) {
        return notNull(value) && value.isEmpty() == false;
    }

    /**
     * 是空集合
     *
     * @param values
     * @return
     */
    public static boolean notEmpty(Object... values) {
        return notNull(values) && values.length > 0;
    }

    /**
     * 是空对象
     *
     * @param value
     * @return
     */
    public static boolean isNull(Object value) {
        return Objects.isNull(value);
    }


    /**
     * 不是空字符
     *
     * @param value
     * @return
     */
    public static boolean notEmpty(String value) {
        return isEmpty(value) == false;
    }

    /**
     * 是否同一个对象
     *
     * @param value
     * @param dest
     * @return
     */
    public static <V> boolean eq(boolean allowNull, V value, V dest) {
        return notNull(allowNull, value, dest::equals);
    }

    /**
     * 比较数据长度
     *
     * @param value
     * @param len
     * @return
     */
    public static <V> boolean len(boolean allowNull, String value, int len) {
        return notNull(allowNull, value, (v) -> value.length() == len);
    }

    /**
     * 比较数据长度
     *
     * @param value
     * @param len
     * @return
     */
    public static <V> boolean len(boolean allowNull, Collection value, int len) {
        return notNull(allowNull, value, (v) -> value.size() == len);
    }

    /**
     * 比较数据长度
     *
     * @param value
     * @param len
     * @return
     */
    public static <V> boolean len(boolean allowNull, V[] value, int len) {
        return notNull(allowNull, value, (v) -> value.length == len);
    }

    /**
     * 数值比较
     *
     * @param value
     * @param compareValue
     * @param type
     * @return
     */
    public static <V> boolean compare(boolean allowNull, V value, V compareValue, CompareType type) {
        return notNull(allowNull, value, (v) -> type.getCompare().compare(value, compareValue));
    }

    /**
     * 比较数值在两个数之间
     *
     * @param value
     * @param minVal
     * @param maxVal
     * @param <V>
     * @return
     */
    public static <V> boolean between(boolean allowNull, V value, V minVal, V maxVal) {
        return compare(allowNull, value, minVal, CompareType.GE) && compare(allowNull, value, maxVal, CompareType.LE);
    }

    /**
     * 比较数值在两个数之间
     *
     * @param value   值
     * @param minVal  最小值
     * @param minType 最小值比较方式
     * @param maxVal  最大值
     * @param maxType 最大值比较方式
     * @param <V>
     * @return
     */
    public static <V> boolean between(boolean allowNull, V value, V minVal, CompareType minType, V maxVal, CompareType maxType) {
        return compare(allowNull, value, minVal, minType) && compare(allowNull, value, maxVal, maxType);
    }

    /**
     * 值在列表内
     *
     * @param value
     * @param values
     * @param <V>
     * @return
     */
    public static <V> boolean in(boolean allowNull, V value, V... values) {
        for (V val : values) {
            if (eq(allowNull, val, value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 值在列表内
     *
     * @param value
     * @param values
     * @param <V>
     * @return
     */
    public static <V> boolean in(boolean allowNull, V value, Collection<V> values) {
        return notNull(allowNull, value, values::contains);
    }

    /**
     * 值正则匹配
     *
     * @param value
     * @param regexp
     * @return
     */
    public static boolean match(boolean allowNull, String value, String regexp) {
        return notNull(allowNull, value, (v) -> value.matches(regexp));
    }

    /**
     * 有效日期时间格式
     *
     * @param value
     * @param format
     * @return
     */
    public static boolean validDate(boolean allowNull, String value, String format) {
        return validDate(allowNull, value, format, (t) -> {
        });
    }

    /**
     * 有效日期时间格式
     *
     * @param value
     * @param format
     * @return
     */
    public static boolean validDate(boolean allowNull, String value, String format, Consumer<Temporal> toConvert) {
        return notNull(allowNull, value, (v) -> notNull(false, format, (f) -> {
            int len = format.length();
            if (value.length() == len) {
                if (len <= 10) {
                    //日期格式
                    String nval;
                    String nformat;
                    if (len == 10 || len == 8) {
                        nval = value;
                        nformat = format;
                    } else if (len == 7) {
                        String ch = format.replaceAll("y|M", "");
                        nval = value + ch + "01";
                        nformat = format + ch + "dd";
                    } else if (len == 6) {
                        nval = value + "01";
                        nformat = format + "dd";
                    } else if (len == 4) {
                        nval = value + "0101";
                        nformat = format + "MMdd";
                    } else {
                        return false;
                    }
                    try {
                        if(DateFormat.YYYY_MM_DD_HH_MM.equals(format)){
                            nval = value + ":01";
                        }
                        LocalDate localDate = DateUtils.parseDate(nval, nformat);
                        String val = localDate.format(DateTimeFormatter.ofPattern(nformat));
                        boolean flag = val.equals(nval);
                        if (flag) {
                            toConvert.accept(localDate);
                        }
                        return flag;
                    } catch (Exception e) {
                        return false;
                    }
                }
                //带时间格式
                try {
                    LocalDateTime localDateTime = DateUtils.parseDateTime(value, format);
                    String val = localDateTime.format(DateTimeFormatter.ofPattern(format));
                    boolean flag = val.equals(value);
                    if (flag) {
                        toConvert.accept(localDateTime);
                    }
                    return flag;
                } catch (Exception e) {
                    return false;
                }
            }
            return false;
        }));
    }
}
